defmodule ChoicePlayground.PageController do
  use ChoicePlayground.Web, :controller
  alias ChoicePlayground.{
    Questionnaire,
    Question,
    QuestionContent,
    Repo,
    ErrorView,
    Choice
  }
  require List
  require Logger

  ################
  # api function #
  ################

  def index(conn, %{"id" => id}) do
    result = get_question(id)
    case result do
      nil ->
        text conn, "not foud"
      _ ->
        render conn, "index.json", question: result
    end
  end

  def answer(conn, %{"id" => id, "answers" => answers}) do
    result = get_question(id)
    case result do
      nil ->
        text conn, "not foud"
      _ ->
        render conn, "answer.json", result: render_answer(result, answers)
    end
  end

  def answer(conn, _) do
    conn |> put_status(400) |> render(ErrorView, "400.json")
  end

  def analysis(conn, %{"id" => id}) do
    result = get_question(id)
    case result do
      nil ->
        text conn, "not foud"
      _ ->
        render conn, "analysis.json", result: render_analysis(result)
    end
  end

  ####################
  ##private function##
  ####################

  defp get_question(id) do
    Questionnaire 
    |> Repo.get_by(seq: String.to_integer(id))
    |> Repo.preload(:question)
  end

  defp render_answer(result, answers) do
    Enum.reduce(result.question, [], fn(q, acc) ->
      res = case q.type do
        "fill" -> 
           Enum.reduce(answers, [], fn(answer, acc) ->
            if answer["id"] == q.seq do
              Choice.add_fill_content(answer["content"], q.id)
              acc = %{title: q.title, content: answer["content"]}
            end
            acc
          end)
        "select" ->
          ans = Enum.filter(answers, fn (answer) -> answer["id"] == q.seq end)
          qc = q |> Repo.preload(:question_content)
          outer = Enum.reduce(qc.question_content, "", fn(content, outer) -> 
            inner = Enum.reduce(List.first(ans)["content"], "", fn(id, inner) ->
              if content.seq === id do
                Choice.update_select_content(content)
                inner = String.trim(inner<>" "<>content.content)
              end
              inner
            end)
            outer = String.trim(outer<>" "<>inner)
          end)
          %{title: q.title, content: String.trim(outer)}
      end
      acc = Enum.concat(acc, [res])
    end)
  end

  defp render_analysis(result) do
    Enum.reduce(result.question, [], fn(item, acc) -> 
      res = %{type: item.type, title: item.title}
      result = case item.type do
        "fill" ->
          Map.put(res, :percent, not_empty_count_percent_of_fill(item))
        "select" ->
          Map.put(res, :options, select_result(item))
      end
      Enum.concat(acc, [result])
    end)
  end


  #####################
  ###helper function###
  #####################

  defp not_empty_count_percent_of_fill(question) do
    fill = question |> Repo.preload(:question_content)
    fill_all = fill.question_content |> length
    fill_empty = Enum.filter(fill.question_content, fn(q) -> q.content == "" end) |> length
    not_empty_count = fill_all - fill_empty
    case fill_all do
      0 -> 0
      _ -> Float.round(not_empty_count/fill_all, 2)
    end
  end

  defp select_result(question) do
    select = question |> Repo.preload(:question_content)
    total = Enum.reduce(select.question_content, 0, fn(q, acc) ->
      acc = acc + q.count
    end)

    Enum.reduce(select.question_content,[],fn(q, acc) ->
      case total do
        0 ->
          res = %{content: q.content, percent: 0}
        _ ->
          res = %{content: q.content, percent: Float.round(q.count/total, 2)}
      end
      Enum.concat(acc, [res])
    end)
  end
end
